#ifndef SIMPLE_IO_SESSION_H
#define SIMPLE_IO_SESSION_H

#include <map>
#include <any>
#include <netinet/in.h>
#include "spdlog/spdlog.h"
#include "reader_buf.h"
#include "writer_buf.h"

namespace simple {
    class Session {
    private:
        // 会话句柄
        int socket_fd_ = 0;
        // 本端地址
        sockaddr_in *local_addr_ = nullptr;
        // 对端地址
        sockaddr_in *remote_addr_ = nullptr;
        // 读取缓冲区
        ReaderBuff readerBuff_;
        // 写入缓冲区
        WriterBuf writerBuff_;
        // 会话载荷, 开放模式, 可按需添加
        std::map<std::string, std::any> attribute_;

    public:
        explicit Session(int socketFd);

        Session(int socketFd, sockaddr_in *localAddr, sockaddr_in *remoteAddr);

        virtual ~Session();

        [[nodiscard]] int socketFd() const;

        ReaderBuff *readerBuff();

        WriterBuf *writerBuff();

        [[nodiscard]] const std::map<std::string, std::any> &attribute() const;

        bool isAttributeExist(const std::string &key) noexcept;

        bool removeAttribute(const std::string &key) noexcept;

        void resetAttribute() noexcept;

        /**
         * 设置属性
         *
         * @param key 属性名
         * @param value 属性值
         * @return 是否设置成功
         */
        template<class T>
        bool setAttribute(const std::string &key, const T &value) noexcept {
            std::any anyValue;
            anyValue.emplace<T>(value);
            this->attribute_[key] = anyValue;
            return true;
        }

        /**
         * 获取属性值
         *
         * @param key 属性名
         * @throw std::invalid_argument 属性不存在
         */
        template<class T>
        T getAttribute(const std::string &key) noexcept(false) {
            if (!this->isAttributeExist(key)) {
                throw std::invalid_argument("Attribute not exist");
            }

            try {
                return std::any_cast<T>(this->attribute_[key]);
            } catch (const std::bad_any_cast &e) {
                throw std::invalid_argument(key + ", attribute type not match, " + std::string(e.what()));
            }
        }

        /**
         * 获取属性值, 如果属性不存在, 返回默认值
         *
         * @param key 属性名
         * @param defaultValue 默认值
         */
        template<class T>
        T getAttribute(const std::string &key, const T &defaultValue) {
            if (!this->isAttributeExist(key)) {
                return defaultValue;
            }
            try {
                return std::any_cast<T>(this->attribute_[key]);
            } catch (const std::bad_any_cast &e) {
                return defaultValue;
            }
        }

        /**
         * 获取属性值, 并移除该属性
         *
         * @param key 属性名
         * @throw std::invalid_argument 属性不存在
         */
        template<class T>
        T popAttribute(const std::string &key) noexcept {
            auto res = this->getAttribute<T>(key);
            this->removeAttribute(key);
            return res;
        }
    };
}

#endif //SIMPLE_IO_SESSION_H
